package com.dgj.utils.db.dao.impl;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;

import org.nutz.dao.Chain;
import org.nutz.dao.Cnd;
import org.nutz.dao.Condition;
import org.nutz.dao.Dao;
import org.nutz.dao.entity.annotation.Column;
import org.nutz.dao.entity.annotation.Id;
import org.nutz.dao.pager.Pager;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.json.Json;
import org.nutz.lang.Lang;
import org.nutz.lang.Mirror;
import org.nutz.lang.util.NutMap;
import org.nutz.log.Logs;

import com.dgj.utils.db.dao.IBaseDao;
import com.dgj.utils.db.data.BakData;
import com.dgj.utils.db.data.Entity;

/**
 * 
 * @author Ixion
 *
 *         nutz dao 实现模板
 * @param <T>
 *            create at 2014年8月22日
 */
@IocBean
public abstract class BaseDao<T extends Entity> implements IBaseDao<T>
{

	@Inject
	protected Dao dao;

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.iofd.ldb.dao.IBaseDao#countAll(java.lang.Class)
	 */
	@Override
	public int countAll()
	{
		return dao.count(initClass());
	}

	@Override
	public Dao getDao()
	{
		return dao;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.iofd.ldb.dao.IBaseDao#countByCnd(java.lang.Class,
	 * org.nutz.dao.Condition)
	 */
	@Override
	public int countByCnd(Condition condition)
	{
		return dao.count(initClass(), condition);
	}

	/**
	 * 
	 */
	@Override
	public void createTable()
	{
		createTable(false);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.kerbores.utils.db.dao.IBaseDao#createTable(boolean)
	 */
	@Override
	public void createTable(boolean drop)
	{
		dao.create(initClass(), drop);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.iofd.ldb.dao.IBaseDao#delById(int, java.lang.Class)
	 */
	@Override
	public boolean delById(int id)
	{

		Entity t = findById(id);// 先查出数据
		BakData data = new BakData(t);// 创建备份
		dao.insert(data);// 保存数据

		return dao.delete(initClass(), id) == 1;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.iofd.ldb.dao.IBaseDao#findAll(java.lang.Class)
	 */
	@Override
	public List<T> findAll()
	{

		return dao.query(initClass(), null);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.iofd.ldb.dao.IBaseDao#findAll(java.lang.Class, java.lang.String)
	 */
	@Override
	public List<T> findAll(String orderby)
	{
		return dao.query(initClass(), Cnd.orderBy().desc(orderby), null);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.iofd.ldb.dao.IBaseDao#findByCondition(java.lang.Class,
	 * org.nutz.dao.Condition)
	 */
	@Override
	public T findByCondition(Condition condition)
	{
		return dao.fetch(initClass(), condition);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.iofd.ldb.dao.IBaseDao#findById(int, java.lang.Class)
	 */
	@Override
	public T findById(long id)
	{
		return dao.fetch(initClass(), id);
	}

	/**
	 * 获取id字段的名称和值
	 * 
	 * @param t
	 * @return
	 */
	private Condition getCnd(T t)
	{
		Mirror<T> clazzMirror = Mirror.me(t);// 获取类型的镜像
		Field idField = null;
		try
		{
			idField = clazzMirror.getField(Id.class);
		} catch (NoSuchFieldException e)
		{
			e.printStackTrace();
		}
		String fieldName = idField.getName();
		Object value = clazzMirror.getValue(t, idField);
		return Cnd.where(fieldName, "=", value);
	}

	/**
	 * 获取当前接口操作的泛型字节码描述
	 * 
	 * @return 要操作的类型的字节码,使Dao接口能获取字节码与数据库之间的映射关系
	 */
	public abstract Class<T> initClass();

	/**
	 * @param t
	 * @param fields
	 * @return
	 */
	private Chain makeChain(T t, String[] fields)
	{
		NutMap map = NutMap.NEW();
		// 获取数据库字段名称和对象值键值对
		Mirror<T> clazzMirror = Mirror.me(t);// 获取类型的镜像
		for (String field : fields)
		{
			Field f = null;
			try
			{
				f = clazzMirror.getField(field);
			} catch (NoSuchFieldException e)
			{
				e.printStackTrace();
			}
			if (f != null)
			{
				map.addv(f.getAnnotation(Column.class).value(), clazzMirror.getValue(t, f));
			}
		}
		return Chain.from(map);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.iofd.ldb.dao.IBaseDao#save(java.lang.Object)
	 */
	@Override
	public T save(T t)
	{
		return dao.insert(t);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.iofd.ldb.dao.IBaseDao#search(java.lang.Class,
	 * org.nutz.dao.Condition)
	 */
	@Override
	public List<T> search(Condition condition)
	{
		return dao.query(initClass(), condition, null);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.iofd.ldb.dao.IBaseDao#searchByPage(java.lang.Class,
	 * org.nutz.dao.Condition, int, int)
	 */
	@Override
	public List<T> searchByPage(Condition condition, int currentPage, int pageSize)
	{
		if (condition == null) {//不传入条件那么我就设置一个排序条件
			condition = Cnd.orderBy().desc("id");
		}
		Pager pager = dao.createPager(currentPage, pageSize);
		return dao.query(initClass(), condition, pager);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.iofd.ldb.dao.IBaseDao#update(java.lang.Object)
	 */
	@Override
	public boolean update(T t)
	{
		return dao.update(t) == 1;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.kerbores.utils.db.dao.IBaseDao#update(java.lang.Object,
	 * java.lang.String[])
	 */
	@Override
	public boolean update(T t, String... fields)
	{
		return dao.update(initClass(), makeChain(t, fields), getCnd(t)) == 1;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.kerbores.utils.db.dao.IBaseDao#updateIgnoreNull(java.lang.Object)
	 */
	@Override
	public boolean updateIgnoreNull(T t)
	{
		return dao.updateIgnoreNull(t) == 1;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.dgj.utils.db.dao.IBaseDao#update(java.lang.Object,
	 * org.nutz.dao.Condition, java.lang.String[])
	 */
	@Override
	public boolean update(T t, Condition cnd, String... fields)
	{
		Arrays.sort(fields);
		NutMap map = Lang.map(Json.toJson(t));
		NutMap data = NutMap.NEW();
		for (String key : map.keySet())
		{
			if (Arrays.binarySearch(fields, key) >= 0)
			{
				data.put(key, map.get(key));
			}
		}
		try
		{
			dao.update(initClass(), Chain.from(data), cnd);
		} catch (Exception e)
		{
			Logs.get().error(e);
			return false;
		}
		return true;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.dgj.utils.db.dao.IBaseDao#update(java.lang.Object,
	 * org.nutz.dao.Condition)
	 */
	@Override
	public boolean update(T t, Condition cnd)
	{
		try
		{
			dao.update(initClass(), Chain.from(t), cnd);
		} catch (Exception e)
		{
			return false;
		}
		return true;
	}

	@Override
	public boolean has(String field, Object value)
	{
		return findByCondition(Cnd.where(field, "=", value)) != null;
	}
}
